#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#include <stdio.h>
#include <stdlib.h>
#include "iniparser.h"


using namespace std;

// 单例配置类
class Configure {
public:
	// 删除拷贝构造函数和赋值运算符
	Configure(const Configure &)            = delete;
	Configure &operator=(const Configure &) = delete;

	// 获取单例实例
	static Configure &Instance() {
		static Configure instance;
		return instance;
	}

	// 配置项访问
	struct {
		string Name    = "DefaultGateway"; // 网关名称
		string Addr    = "0.0.0.0";        // 网关地址
		uint16_t Port  = 8080;             // 网关端口
		uint16_t Agent = 8081;             // 代理端口
	} Gateway;

	// 广播配置
	struct {
		string Addr       = "255.255.255.255"; // 广播地址
		uint16_t Port     = 9999;              // 广播端口
		uint16_t Interval = 5000;              // 间隔时间(毫秒)
	} Broadcast;

	// 注册中心配置
	struct {
		string Addr       = "127.0.0.1"; // 注册中心IP
		uint16_t Port     = 8500;        // 注册中心端口
		uint16_t Interval = 5000;        // 服务同步周期
	} Discovery;

	// 日志配置
	struct {
		string Level = "info";       // debug|info|warn|error|fatal|panic
		string Path  = "./dump.log"; // 日志文件路径
		bool Quiet   = false;        // 是否静默(不输出到文件)
	} Logger;

	// 服务信息
	struct Service {
		string Name;   // 服务名称
		string Addr;   // 服务地址
		uint16_t Port; // 服务端口
		bool Enable;   // 是否启用

		// 编码，如：HelloService|192.168.1.101|8001|1
		std::string encode(const Service &service) {
			std::ostringstream oss;
			oss << service.Name << "|" << service.Addr << "|" << service.Port << "|" << (service.Enable ? 1 : 0);
			return oss.str();
		}

		// 格式: HelloService|192.168.1.101|8001|0
		static Service decode(const std::string &encoded) {
			Service service;
			std::istringstream iss(encoded);
			std::string token;
			std::getline(iss, service.Name, '|');
			std::getline(iss, service.Addr, '|');
			std::getline(iss, token, '|');
			service.Port = static_cast<uint16_t>(std::stoi(token));
			std::getline(iss, token, '|');
			service.Enable = (std::stoi(token) != 0);
			return service;
		}
	};

	vector<Service> Services;

	// 加载配置（支持指定文件路径）
	void Load(const string &configPath = "etc/config.ini") {
		dictionary *ini = iniparser_load(configPath.c_str());
		if (ini == NULL) {
			printf("config path error, use default settings\n");
		}

		// 解析基础配置
		const char *str = iniparser_getstring(ini, "Gateway:Addr", NULL);
		if (str != NULL) Gateway.Addr = str;
		int num = iniparser_getint(ini, "Gateway:Port", -1);
		if (num > 0) Gateway.Port = num;
		num = iniparser_getint(ini, "Gateway:Agent", -1);
		if (num > 0) Gateway.Agent = num;

		// 解析广播配置
		str = iniparser_getstring(ini, "Broadcast:Addr", NULL);
		if (str != NULL) Broadcast.Addr = str;
		num = iniparser_getint(ini, "Broadcast:Port", -1);
		if (num > 0) Broadcast.Port = num;
		num = iniparser_getint(ini, "Broadcast:Interval", -1);

		// 解析注册中心配置
		str = iniparser_getstring(ini, "Discovery:Addr", NULL);
		if (str != NULL) Discovery.Addr = str;
		num = iniparser_getint(ini, "Discovery:Port", -1);
		if (num > 0) Discovery.Port = num;
		num = iniparser_getint(ini, "Discovery:Interval", -1);

		// 解析日志配置
		str = iniparser_getstring(ini, "Logger:Level", NULL);
		if (str != NULL) Logger.Level = str;
		str = iniparser_getstring(ini, "Logger:Path", NULL);
		if (str != NULL) Logger.Path = str;
		num = iniparser_getint(ini, "Logger:Quiet", -1);
		if (num > 0) Logger.Quiet = true;

		// 解析服务配置
		Services.clear();
		for (int i = 1;; ++i) {
			char section[32];
			snprintf(section, sizeof(section), "Services:Service.%d", i);
			str = iniparser_getstring(ini, section, NULL);
			if (str == NULL) break;
			Services.push_back(Service::decode(str));
		}
	}

private:
	Configure()  = default; // 私有构造函数
	~Configure() = default; // 私有析构函数
};

// gcc -std=c11 -I../libs -c ../libs/*.c
// g++ -std=c++11 -I../libs config.cpp ../libs/*.c -o config.exe
int main() {
	// 获取配置实例
	auto &config = Configure::Instance();
	config.Load("config_example.ini");

	// 打印配置
	std::cout << "Gateway: " << config.Gateway.Addr << ":" << config.Gateway.Port << std::endl;
	std::cout << "Broadcast: " << config.Broadcast.Addr << ":" << config.Broadcast.Port << std::endl;
	std::cout << "Discovery: " << config.Discovery.Addr << ":" << config.Discovery.Port << std::endl;
	std::cout << "Logger.Level: " << config.Logger.Level << std::endl;
	std::cout << "Logger.Path: " << config.Logger.Path << std::endl;
	std::cout << "Logger.Quiet: " << (config.Logger.Quiet ? "true" : "false") << std::endl;
	std::cout << "Services:" << std::endl;
	for (const auto &service: config.Services) {
		std::cout << "  " << service.Name << ": " << service.Addr << ":" << service.Port << " " << (service.Enable ? "true" : "false") << std::endl;
	}
	return 0;
}
